package qc.module.qms.service.pointdata;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.constants.QmsConstant;
import qc.common.core.enums.qms.QmsPointTimeSegmentEnum;
import qc.common.core.utils.LocalDateTimeUtil;
import qc.module.qms.dto.pointdata.QmsPointNumericDataDto;
import qc.module.qms.entity.QmsPointDataLatest;
import qc.module.qms.repository.QmsPointDataLatestRepository;

import java.time.LocalDateTime;

/**
 * QMS点号数据最新状态Service
 *
 * @author QuCheng Tech
 * @since 2025/10/4
 */
@Service
public class QmsPointDataLatestService {
    @Autowired
    private QmsPointDataLatestRepository repository;

    /**
     * 获取指定点号的最新定时计算数据时标，返回null表示没有记录或者记录中的最新定时计算数据时标为null
     *
     * @param pointid 点号
     * @param tmseg   点号时段类型
     * @return java.time.LocalDateTime
     * @author QuCheng Tech
     * @since 2025/10/4
     */
    public LocalDateTime getCalcDataTime(String pointid, QmsPointTimeSegmentEnum tmseg) {
        //如果传入条件错误不进行查询
        if (StringUtils.isNotBlank(pointid) && tmseg != null && tmseg != QmsPointTimeSegmentEnum.UN_DEFINE) {
            LambdaQueryWrapper<QmsPointDataLatest> wrapper = new LambdaQueryWrapper<>();
            //只查询定时计算的数据时标
            wrapper.select(QmsPointDataLatest::getCalctm);

            //条件：点号相同、时段类型相同
            wrapper.eq(QmsPointDataLatest::getPointid, pointid);
            wrapper.eq(QmsPointDataLatest::getTmseg, tmseg);

            //查询数据
            QmsPointDataLatest en = repository.selectOne(wrapper);
            if (en != null)
                return en.getCalctm();
        }

        return null;
    }

    /**
     * 更新指定点号的最新定时计算数据时标
     *
     * @param pointid     点号
     * @param tmseg       点号时段类型
     * @param datatime    最新定时计算数据时标
     * @param forceUpdate 是否为强制更新，强制更新时不管已有记录的时间均使用本次进行更新
     * @return void
     * @author QuCheng Tech
     * @since 2025/10/4
     */
    public void updateCalcDataTime(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime datatime, boolean forceUpdate) {
        //如果传入条件错误不进行操作
        if (StringUtils.isNotBlank(pointid) && tmseg != null && tmseg != QmsPointTimeSegmentEnum.UN_DEFINE && datatime != null) {
            LocalDateTime now = LocalDateTimeUtil.getNow();

            QmsPointDataLatest exist = this.get(pointid, tmseg);
            this.getCalcDataTime(pointid, tmseg);
            if (exist != null) {
                LocalDateTime existCalcDataTime = exist == null ? null : exist.getCalctm();
                //需要判断定时计算的时间，如果本次计算时间＜已有的时间，不进行更新
                if (forceUpdate == true || existCalcDataTime == null || datatime.isAfter(existCalcDataTime)) {
                    //存在点号记录，进行update
                    LambdaUpdateWrapper<QmsPointDataLatest> wrapper = new LambdaUpdateWrapper<>();
                    //条件：点号相同、时段类型相同
                    wrapper.eq(QmsPointDataLatest::getPointid, pointid);
                    wrapper.eq(QmsPointDataLatest::getTmseg, tmseg);
                    //指定更新的字段
                    wrapper.set(QmsPointDataLatest::getCalctm, datatime);
                    wrapper.set(QmsPointDataLatest::getCalcuptm, now);

                    repository.update(null, wrapper);
                }
            } else {
                //不存在点号记录，进行insert
                QmsPointDataLatest en = new QmsPointDataLatest();
                //赋值字段
                en.setPointid(pointid);
                en.setTmseg(tmseg);
                en.setCalctm(datatime);
                en.setCalcuptm(now);
                //其他置空字段
                en.setTm(null);
                en.setV(null);
                en.setBeginv(null);
                en.setEndv(null);
                en.setMaxv(null);
                en.setMaxtm(null);
                en.setMinv(null);
                en.setMintm(null);
                en.setRawtm(null);
                en.setRawvalue(null);
                en.setRawuptm(null);
                en.setUptm(null);

                repository.insert(en);
            }
        }
    }

    /**
     * 判断指定点号的记录是否存在
     *
     * @param pointid 点号
     * @param tmseg   点号时段类型
     * @return boolean
     * @author QuCheng Tech
     * @since 2025/10/4
     */
    boolean exist(String pointid, QmsPointTimeSegmentEnum tmseg) {
        //如果传入条件错误不进行查询
        if (StringUtils.isNotBlank(pointid) && tmseg != null && tmseg != QmsPointTimeSegmentEnum.UN_DEFINE) {
            LambdaQueryWrapper<QmsPointDataLatest> wrapper = new LambdaQueryWrapper<>();
            //只查询点号ID
            wrapper.select(QmsPointDataLatest::getPointid);

            //条件：点号相同、时段类型相同
            wrapper.eq(QmsPointDataLatest::getPointid, pointid);
            wrapper.eq(QmsPointDataLatest::getTmseg, tmseg);

            //查询数据
            QmsPointDataLatest en = repository.selectOne(wrapper);
            if (en != null)
                return true;
        }

        return false;
    }

    /**
     * 获取指定点号的完整信息
     *
     * @param pointid 点号
     * @param tmseg   点号时段类型
     * @return qc.module.qms.entity.QmsPointDataLatest
     * @author QuCheng Tech
     * @since 2025/10/10
     */
    public QmsPointDataLatest get(String pointid, QmsPointTimeSegmentEnum tmseg) {
        //如果传入条件错误不进行查询
        if (StringUtils.isNotBlank(pointid) && tmseg != null && tmseg != QmsPointTimeSegmentEnum.UN_DEFINE) {
            LambdaQueryWrapper<QmsPointDataLatest> wrapper = new LambdaQueryWrapper<>();

            //条件：点号相同、时段类型相同
            wrapper.eq(QmsPointDataLatest::getPointid, pointid);
            wrapper.eq(QmsPointDataLatest::getTmseg, tmseg);

            //查询数据
            return repository.selectOne(wrapper);
        }

        return null;
    }

    /**
     * 更新点号数据最新状态
     *
     * @param pointid     点号
     * @param tmseg       点号时段类型
     * @param forceUpdate 是否为强制更新，强制更新时不管已有记录的时间均使用本次进行更新
     * @param data        用于更新的点号数据，可以为null
     * @return void
     * @author QuCheng Tech
     * @since 2025/10/10
     */
    public void updatePointData(String pointid, QmsPointTimeSegmentEnum tmseg, boolean forceUpdate, QmsPointNumericDataDto data) {
        //如果传入条件错误不进行操作
        if (StringUtils.isNotBlank(pointid) && tmseg != null && tmseg != QmsPointTimeSegmentEnum.UN_DEFINE) {
            LocalDateTime now = LocalDateTimeUtil.getNow();
            //判断传入的点号数据是否有效，根据数据质量判断
            if (data != null) {
                //如果传入的点号数据质量无效，设置点号数据为null
                if (data.getQuality().getIndex() < QmsConstant.POINT_DATA_VALID_QUALITY_FROM.getIndex())
                    data = null;
            }

            QmsPointDataLatest exist = this.get(pointid, tmseg);
            if (exist != null) {
                //如果传入的本次要更新的数据为null并且是强制更新模式，设置所有的数据值为null
                if (data == null && forceUpdate == true) {
                    LambdaUpdateWrapper<QmsPointDataLatest> wrapper = new LambdaUpdateWrapper<>();
                    //条件：点号相同、时段类型相同
                    wrapper.eq(QmsPointDataLatest::getPointid, pointid);
                    wrapper.eq(QmsPointDataLatest::getTmseg, tmseg);
                    //指定更新的字段
                    wrapper.set(QmsPointDataLatest::getTm, null);
                    wrapper.set(QmsPointDataLatest::getV, null);
                    wrapper.set(QmsPointDataLatest::getBeginv, null);
                    wrapper.set(QmsPointDataLatest::getEndv, null);
                    wrapper.set(QmsPointDataLatest::getMaxv, null);
                    wrapper.set(QmsPointDataLatest::getMaxtm, null);
                    wrapper.set(QmsPointDataLatest::getMinv, null);
                    wrapper.set(QmsPointDataLatest::getMintm, null);
                    wrapper.set(QmsPointDataLatest::getQuality, null);
                    wrapper.set(QmsPointDataLatest::getUptm, now);

                    repository.update(null, wrapper);
                } else if (data.getTm() != null) {
                    //需要判断定时计算的时间，如果已有的数据时标＞本次数据时标，不进行更新
                    if (forceUpdate == true || exist.getTm() == null || exist.getTm().isAfter(data.getTm()) == false) {
                        //存在点号记录，进行update
                        LambdaUpdateWrapper<QmsPointDataLatest> wrapper = new LambdaUpdateWrapper<>();
                        //条件：点号相同、时段类型相同
                        wrapper.eq(QmsPointDataLatest::getPointid, pointid);
                        wrapper.eq(QmsPointDataLatest::getTmseg, tmseg);
                        //指定更新的字段
                        wrapper.set(QmsPointDataLatest::getTm, data.getTm());
                        wrapper.set(QmsPointDataLatest::getV, data.getV());
                        wrapper.set(QmsPointDataLatest::getBeginv, data.getBeginv());
                        wrapper.set(QmsPointDataLatest::getEndv, data.getEndv());
                        wrapper.set(QmsPointDataLatest::getMaxv, data.getMaxv());
                        wrapper.set(QmsPointDataLatest::getMaxtm, data.getMaxtm());
                        wrapper.set(QmsPointDataLatest::getMinv, data.getMinv());
                        wrapper.set(QmsPointDataLatest::getMintm, data.getMintm());
                        wrapper.set(QmsPointDataLatest::getQuality, data.getQuality());
                        wrapper.set(QmsPointDataLatest::getUptm, now);

                        repository.update(null, wrapper);
                    }
                }
            } else {
                //不存在点号最新状态记录，进行insert
                if (data != null && data.getTm() != null) {
                    //如果没有点号最新状态记录，传入的data无效不进行新增
                    QmsPointDataLatest en = new QmsPointDataLatest();
                    //赋值字段
                    en.setPointid(pointid);
                    en.setTmseg(tmseg);
                    //点号数据字段
                    en.setTm(data.getTm());
                    en.setV(data.getV());
                    en.setBeginv(data.getBeginv());
                    en.setEndv(data.getEndv());
                    en.setMaxv(data.getMaxv());
                    en.setMaxtm(data.getMaxtm());
                    en.setMinv(data.getMinv());
                    en.setMintm(data.getMintm());
                    en.setQuality(data.getQuality());
                    en.setUptm(now);
                    //其他字段保持为null
                    en.setCalctm(null);
                    en.setCalcuptm(null);
                    en.setRawtm(null);
                    en.setRawvalue(null);
                    en.setRawuptm(null);

                    repository.insert(en);
                }
            }
        }
    }

    /**
     * 获取指定定号的最新原始数据时标，返回null表示没有记录或者记录中的原始数据时标为null
     *
     * @param pointid 点号
     * @param tmseg   点号时段类型
     * @return java.time.LocalDateTime
     * @author QuCheng Tech
     * @since 2025/10/11
     */
    public LocalDateTime getRawDataTime(String pointid, QmsPointTimeSegmentEnum tmseg) {
        //如果传入条件错误不进行查询
        if (StringUtils.isNotBlank(pointid) && tmseg != null && tmseg != QmsPointTimeSegmentEnum.UN_DEFINE) {
            LambdaQueryWrapper<QmsPointDataLatest> wrapper = new LambdaQueryWrapper<>();
            //只查询定时原始数据的数据时标
            wrapper.select(QmsPointDataLatest::getRawtm);

            //条件：点号相同、时段类型相同
            wrapper.eq(QmsPointDataLatest::getPointid, pointid);
            wrapper.eq(QmsPointDataLatest::getTmseg, tmseg);

            //查询数据
            QmsPointDataLatest en = repository.selectOne(wrapper);
            if (en != null)
                return en.getRawtm();
        }

        return null;
    }

    /**
     * 更新指定点号的最新原始数据信息，更新原始数据时标和数据值
     *
     * @param pointid     点号
     * @param tmseg       点号时段类型
     * @param datatime    原始数据时标
     * @param datavalue   原始数据值
     * @param forceUpdate 是否为强制更新，强制更新时不管已有记录的时间均使用本次进行更新
     * @return void
     * @author QuCheng Tech
     * @since 2025/10/11
     */
    public void updateRawData(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime datatime, Double datavalue, boolean forceUpdate) {
        //如果传入条件错误不进行操作
        if (StringUtils.isNotBlank(pointid) && tmseg != null && tmseg != QmsPointTimeSegmentEnum.UN_DEFINE && datatime != null) {
            LocalDateTime now = LocalDateTimeUtil.getNow();

            LocalDateTime existRawDataTime = this.getRawDataTime(pointid, tmseg);
            if (existRawDataTime != null) {
                //需要判断原始数据的时间，如果本次数据时间＜已有的时间，不进行更新
                if (forceUpdate == true || datatime.isAfter(existRawDataTime)) {
                    //存在点号记录，进行update
                    LambdaUpdateWrapper<QmsPointDataLatest> wrapper = new LambdaUpdateWrapper<>();
                    //条件：点号相同、时段类型相同
                    wrapper.eq(QmsPointDataLatest::getPointid, pointid);
                    wrapper.eq(QmsPointDataLatest::getTmseg, tmseg);
                    //指定更新的字段
                    wrapper.set(QmsPointDataLatest::getRawtm, datatime);
                    wrapper.set(QmsPointDataLatest::getRawvalue, datavalue);
                    wrapper.set(QmsPointDataLatest::getRawuptm, now);

                    repository.update(null, wrapper);
                }
            } else {
                //不存在点号记录，进行insert
                QmsPointDataLatest en = new QmsPointDataLatest();
                //赋值字段
                en.setPointid(pointid);
                en.setTmseg(tmseg);
                en.setRawtm(datatime);
                en.setRawvalue(datavalue);
                en.setRawuptm(now);
                //其他置空字段
                en.setTm(null);
                en.setV(null);
                en.setBeginv(null);
                en.setEndv(null);
                en.setMaxv(null);
                en.setMaxtm(null);
                en.setMinv(null);
                en.setMintm(null);
                en.setUptm(null);
                en.setCalctm(null);
                en.setCalcuptm(null);

                repository.insert(en);
            }
        }
    }
}
